// Copyright (c) Microsoft Corporation.  All rights reserved.

#include "stdafx.h"
#include <vector>

#include "DXGIOutput.h"
#include "DXGISurface.h"
#include "DXGIDevice.h"
#include "Direct3D11/D3D11Device.h"
#include "Direct3D10/D3D10Device.h"

using namespace std;
using namespace System::Collections::Generic;
using namespace System::Collections::ObjectModel;
using namespace Microsoft::WindowsAPICodePack::DirectX::DXGI;

using namespace Microsoft::WindowsAPICodePack::DirectX::Direct3DCommon;

ModeDescription^ Output::FindClosestMatchingMode(ModeDescription^ ModeToMatch, Microsoft::WindowsAPICodePack::DirectX::Direct3D10::D3DDevice^ ConcernedDevice)
{
    DXGI_MODE_DESC* tempoutClosestMatch = new DXGI_MODE_DESC();
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->FindClosestMatchingMode(
        ModeToMatch->nativeObject.Get(), tempoutClosestMatch, (ConcernedDevice == nullptr ? NULL : ConcernedDevice->GetInterface<IUnknown>())));
    return gcnew ModeDescription(tempoutClosestMatch);
}

ModeDescription^ Output::FindClosestMatchingMode(ModeDescription^ ModeToMatch, Microsoft::WindowsAPICodePack::DirectX::Direct3D11::D3DDevice^ ConcernedDevice)
{
    DXGI_MODE_DESC* tempoutClosestMatch = new DXGI_MODE_DESC();
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->FindClosestMatchingMode(
        ModeToMatch->nativeObject.Get(), tempoutClosestMatch, (ConcernedDevice == nullptr ? NULL : ConcernedDevice->GetInterface<IUnknown>())));
    return gcnew ModeDescription(tempoutClosestMatch);
}

ModeDescription^ Output::FindClosestMatchingMode(ModeDescription^ ModeToMatch)
{
    DXGI_MODE_DESC* tempoutClosestMatch = new DXGI_MODE_DESC();
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->FindClosestMatchingMode(ModeToMatch->nativeObject.Get(), tempoutClosestMatch, NULL));
    
    return gcnew ModeDescription(tempoutClosestMatch);
}

UInt32 Output::GetNumberOfDisplayModes(Format colorFormat, EnumModes flags)
{
    UINT outNumModes = 0;

    CommonUtils::VerifyResult(
        GetInterface<IDXGIOutput>()->GetDisplayModeList(
        static_cast<DXGI_FORMAT>(colorFormat), static_cast<UINT>(flags), &outNumModes, NULL));

    return outNumModes;
}

ReadOnlyCollection<ModeDescription^>^ Output::GetDisplayModeList(Format colorFormat, EnumModes flags)
{
    UINT numModes = GetNumberOfDisplayModes(colorFormat, flags);

    IList<ModeDescription^>^ list = gcnew List<ModeDescription^>();

    if (numModes > 0)
    {
        vector<DXGI_MODE_DESC> descriptions(numModes);

        CommonUtils::VerifyResult(
            GetInterface<IDXGIOutput>()->GetDisplayModeList(
            static_cast<DXGI_FORMAT>(colorFormat), static_cast<UINT>(flags), &numModes, &descriptions[0]));
        
            
        for (UINT i = 0; i < numModes; i++)
        {
            list->Add(gcnew ModeDescription(descriptions[i]));
        }
    }

    return gcnew ReadOnlyCollection<ModeDescription^>(list);
}
OutputDescription^ Output::GetDescription()
{
    OutputDescription^ desc = gcnew OutputDescription();
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->GetDesc(desc->nativeObject.Get()));

    return desc;
}

void Output::GetDisplaySurfaceData(Surface^ Destination)
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->GetDisplaySurfaceData(Destination->GetInterface<IDXGISurface>()));
}

FrameStatistics^ Output::GetRenderedFrameStatistics()
{
    DXGI_FRAME_STATISTICS* tempoutStats = new DXGI_FRAME_STATISTICS();
    ZeroMemory(tempoutStats, sizeof(DXGI_FRAME_STATISTICS));
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->GetFrameStatistics(tempoutStats));
    
    return gcnew FrameStatistics(tempoutStats);
}

GammaControl^ Output::GetGammaControl()
{
    GammaControl^ ctrl = gcnew GammaControl();
    
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->GetGammaControl(ctrl->nativeObject.Get()));

    return ctrl;
}

void Output::SetGammaControl(GammaControl^ gammaControl)
{
    if (gammaControl == nullptr)
        throw gcnew ArgumentNullException("gammaControl");

    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->SetGammaControl(gammaControl->nativeObject.Get()));
}

GammaControlCapabilities^ Output::GetGammaControlCapabilities()
{
    GammaControlCapabilities^ caps = gcnew GammaControlCapabilities();
                
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->GetGammaControlCapabilities(caps->nativeObject.Get()));

    return caps;
}

void Output::SetDisplaySurface(Surface^ ScanoutSurface)
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->SetDisplaySurface(ScanoutSurface->GetInterface<IDXGISurface>()));
}

void Output::ReleaseOwnership()
{
    GetInterface<IDXGIOutput>()->ReleaseOwnership();
}
void Output::TakeOwnership(Microsoft::WindowsAPICodePack::DirectX::Direct3D10::D3DDevice^ device, Boolean exclusive)
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->TakeOwnership(device->GetInterface<IUnknown>(), safe_cast<BOOL>(exclusive)));
}

void Output::TakeOwnership(Microsoft::WindowsAPICodePack::DirectX::Direct3D11::D3DDevice^ device, Boolean exclusive)
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->TakeOwnership(device->GetInterface<IUnknown>(), safe_cast<BOOL>(exclusive)));
}

void Output::TakeOwnership(DXGIDevice^ device, Boolean exclusive)
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->TakeOwnership(device->GetInterface<IDXGIDevice>(), safe_cast<BOOL>(exclusive)));
}
void Output::WaitForVBlank()
{
    CommonUtils::VerifyResult(GetInterface<IDXGIOutput>()->WaitForVBlank());
}

